perm filename INSTRU.SAI[REV,MUS] blob
sn#254451 filedate 1977-05-24 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00007 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002 ENTRY
C00003 00003 ∂ Declarations for unit reverberator manipulation routines.
C00005 00004 ∂ Declarations for tree manipulation routines.
C00007 00005 INTERNAL PROCEDURE instrument_print(
C00011 00006 ∂ ... instrument_print ... continued.
C00016 00007 END "INSTRU"
C00017 ENDMK
C⊗;
ENTRY;
BEGIN "INSTRU"
REQUIRE "HEADER.SAI" SOURCE_FILE;
∂ Ken Shoemake. December 1976.
This module prints out a reverberator tree as an instrument for the
music compiler to read.
;
∂ Declarations for unit reverberator manipulation routines.;
EXTERNAL RECORD_CLASS REV_UNIT(
INTEGER NUMBER_OF_SAMPLES, CLOCK_RATE;
REAL GAIN, DELAY_TIME, DECAY_TIME);
EXTERNAL REAL PROCEDURE get_spec(
RECORD_POINTER(REV_UNIT) unit;
STRING which_spec);
EXTERNAL REAL PROCEDURE set_spec(
RECORD_POINTER(REV_UNIT) unit;
STRING new_spec, fix_spec;
REAL spec_val;
BOOLEAN use_prime(TRUE));
EXTERNAL RECORD_POINTER(REV_UNIT) PROCEDURE new_unit(
INTEGER rate(0);
REAL gain(0), delay(0);
BOOLEAN use_prime(TRUE));
EXTERNAL PROCEDURE free_unit(
REFERENCE RECORD_POINTER(REV_UNIT) unit);
EXTERNAL PROCEDURE copy_unit(
REFERENCE RECORD_POINTER(REV_UNIT) new_copy;
RECORD_POINTER(REV_UNIT) unit);
EXTERNAL INTEGER PROCEDURE nearest_prime(
REFERENCE INTEGER n);
EXTERNAL INTEGER ARRAY PRIMES[1:2]; ∂ Bounds are ignored.;
∂ Declarations for tree manipulation routines.;
EXTERNAL RECORD_CLASS REV_TREE(
RECORD_POINTER(REV_TREE) IN, OUT, ABURO;
RECORD_POINTER(REV_UNIT) UNIT);
EXTERNAL PROCEDURE insert_node(
REFERENCE RECORD_POINTER(REV_TREE) node;
RECORD_POINTER(REV_UNIT) unit;
STRING direction("OUTPUT");
BOOLEAN replace(FALSE));
EXTERNAL PROCEDURE first_node(
REFERENCE RECORD_POINTER(REV_TREE) node);
EXTERNAL BOOLEAN PROCEDURE move_tree(
REFERENCE RECORD_POINTER(REV_TREE) node;
REFERENCE RECORD_POINTER(REV_UNIT) unit;
STRING direction("OUTPUT"));
EXTERNAL PROCEDURE free_node(
REFERENCE RECORD_POINTER(REV_TREE) node);
EXTERNAL PROCEDURE delete_node(
REFERENCE RECORD_POINTER(REV_TREE) node);
EXTERNAL BOOLEAN PROCEDURE traverse_tree(
REFERENCE RECORD_POINTER(REV_TREE) node;
REFERENCE RECORD_POINTER(REV_UNIT) unit;
REFERENCE INTEGER level;
REFERENCE BOOLEAN branching);
EXTERNAL BOOLEAN PROCEDURE is_root(
RECORD_POINTER(REV_TREE) node);
EXTERNAL RECORD_POINTER(REV_TREE) PROCEDURE new_tree;
EXTERNAL PROCEDURE free_tree(
REFERENCE RECORD_POINTER(REV_TREE) node);
INTERNAL PROCEDURE instrument_print(
INTEGER channel;
RECORD_POINTER(REV_TREE) node);
∂ Translate the tree to form readable by music compiler, and print on
the given channel. Currently at most 4 channels of output are allowed,
OUTA OUTB OUTC and OUTD. If a tree has more than 4 leaves, the last 4
encountered in the standard traversal are used. Output on each channel
is normalized to compensate for the effects of the reverberator
attenuation. The indentation format used is the same as that used in
REVED for screen display.
;
BEGIN "instrument print"
RECORD_POINTER(REV_TREE) tree, tmp_tree;
RECORD_POINTER(REV_UNIT) unit, tmp_unit;
INTEGER indent_level, indent,
previous_level, out_index,
rate, sum_of_#samples,
count,
wid, dig;
REAL minimum_distance, time, gain;
BOOLEAN branching;
STRING ARRAY stack[0:20],
outputs[0:3];
REAL ARRAY norms[0:3];
STRING signal_source;
GETFORMAT(wid,dig);
SETFORMAT(0,2);
tree ← node;
first_node(tree);
IF
¬traverse_tree(tree,unit,indent_level,branching)
THEN
RETURN;
rate ← get_spec(unit,"rate");
time ← get_spec(unit,"decay");
CPRINT(channel,
↓,
"VARIABLE /DSIG;",↓
);
CPRINT(channel,
"ARRAY R1[",CVS(get_spec(unit,"#samples")+1),"]"
);
sum_of_#samples ← get_spec(unit,"#samples")+1;
minimum_distance ← get_spec(unit,"wall");
count ← 1;
WHILE
traverse_tree(tree,unit,indent_level,branching)
DO BEGIN
count ← count+1;
IF
count MOD 6 = 1
THEN
CPRINT(channel,
↓,TAB);
CPRINT(channel,
",R",count,"[",CVS(get_spec(unit,"#samples")+1),"]");
sum_of_#samples ← sum_of_#samples+get_spec(unit,"#samples")+1;
minimum_distance ← minimum_distance MIN get_spec(unit,"wall");
END;
CPRINT(channel, ";",↓,
↓,
"COMMENT: Sum of delay memory sizes = ",sum_of_#samples,↓,
TAB, " Reverberation time =",CVF(time)," seconds",↓,
TAB, " Clock rate = ",rate,↓,
TAB, " Distance to first reflector =",
CVF(minimum_distance)," meters",";",↓
);
∂ ... instrument_print ... continued.;
CPRINT(channel,
↓,
"INSTRUMENT ALLPASS;",↓,
"I_ONLY",↓,
" BEGIN",↓,
TAB, "PRINT "" ALLPASS REVERB "";",↓,
TAB, "REVINIT←1;",↓,
TAB, "IF",↓,
TAB, " SRATE ≠ ",rate,↓,
TAB, " THEN",↓,
TAB, " PRINT """,↓,
"WARNING: SRATE does not match reverberator rate. "";",↓,
" END;",↓,
↓);
stack[0] ← "DSIG";
DEFINE PROCESS_LEAF=⊂
BEGIN
outputs[out_index ← ((out_index+1) MOD 4)] ←
stack[previous_level];
gain ← get_spec(tmp_unit,"gain");
WHILE
move_tree(tmp_tree,tmp_unit,"INPUT")
∧
¬is_root(tmp_tree)
DO
gain ← gain*get_spec(tmp_unit,"gain");
norms[out_index] ← 1.0/gain;
END
⊃;
indent_level ← 0; branching ← FALSE;
count ← 0;
previous_level ← 0; out_index ← 3;
tmp_tree ← tree; copy_unit(tmp_unit,unit);
SETFORMAT(0,3);
WHILE
traverse_tree(tree,unit,indent_level,branching)
DO BEGIN
IF
indent_level ≤ previous_level
THEN
PROCESS_LEAF;
count ← count+1;
signal_source ← stack[indent_level-1];
IF
¬branching
THEN
indent_level ← 0;
previous_level ← indent_level;
tmp_tree ← tree; copy_unit(tmp_unit,unit);
stack[indent_level] ← "U"&CVS(count);
FOR
indent ← 1
THRU
indent_level
DO
CPRINT(channel, " ");
CPRINT(channel,
"REV2(",signal_source,",",
CVS(get_spec(unit,"#samples")),",",
CVF(get_spec(unit,"gain")),",",
"R",count,");",
↓);
END;
PROCESS_LEAF;
FOR
out_index ← 0
THRU
3
DO
IF
outputs[out_index] ≠ NULL
THEN
CPRINT(channel,
"OUT",("A"+out_index)&NULL,
" ← OUT",("A"+out_index)&NULL,
"+",outputs[out_index],
"*",CVF(norms[out_index])[2 TO ∞],";",↓
);
CPRINT(channel,
"DSIG←0;",↓,
"END;",↓
);
SETFORMAT(wid,dig);
END "instrument print";
END "INSTRU"